/**
 * 
 */
package de.dnb.basics.statistics;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import de.dnb.basics.applicationComponents.Pair;

/**
 * Zählt die Häufigkeit einer Kombination mehrerer Merkmale. Diese 
 * Merkmalskombination kann als Element des Kartesischen Produktes mehrerer 
 * Merkmalsmengen aufgefasst werden.
 * 
 * Genauer: Es wird die Funktion <br>
 * <code>#(i<sub>1</sub>, i<sub>2</sub>, ..., i<sub>n</sub>), 
 * i<sub>k</sub> &isin; M<sub>k</sub></code> 
 * <br> nachgebildet
 * 
 * @author Christian_2
 *
 */
public class CrossProductFrequency extends
	Frequency<Collection<? extends Object>> {

	/**
	 * Erhöht den Zähler für die Merkmalskombination values um 1.
	 * 
	 * @param values	beliebig
	 */
	public final void addValues(final Object... values) {
		List<Object> v = Arrays.asList(values);
		//		System.err.println("add:" + v);
		Long l = values2long.get(v);
		if (l == null) {
			l = new Long(1);
		} else {
			l++;
		}
		values2long.put(v, l);
	}

	/**
	 * Erhöht den Zähler für die Merkmalskombination values um increment.
	 * 
	 * @param increment	beliebig
	 * @param objects	beliebig
	 */
	public final void incrementValues(
		final long increment,
		final Object... objects) {
		List<Object> v = Arrays.asList(objects);
		//		System.err.println("inc:" + v);
		Long l = values2long.get(v);
		if (l == null) {

			l = new Long(increment);
		} else {
			l += increment;
		}
		values2long.put(v, l);
	}

	/**
	 * Liefert eine reduzierte Verteilungsfunktion mit weniger Merkmalen.
	 * Über die nicht interessierenden Merkmale wird summiert.
	 * 
	 * 
	 * @param remainingIndices	Indices der beibehaltene Merkmale, größer 0
	 * @return					neue Verteilungsfunktion
	 */
	public final CrossProductFrequency getPartialSum(
		final int... remainingIndices) {
		// Maximum finden:
		int max = Integer.MIN_VALUE;
		for (int i : remainingIndices) {
			if (i < 0)
				throw new IllegalArgumentException("beizubehaltender Index "
					+ i + " ist negativ");
			max = Math.max(max, i);
		}

		CrossProductFrequency newFrequency = new CrossProductFrequency();
		Iterator<Collection<? extends Object>> iterator = valuesIterator();
		for (; iterator.hasNext();) {
			Object[] nextValues = iterator.next().toArray();
			if (nextValues.length > max) {
				List<Object> reducedValues = new ArrayList<>();
				for (int i : remainingIndices) {
					Object value = nextValues[i];
					reducedValues.add(value);
				}
				newFrequency.incrementValues(getCount(nextValues),
					reducedValues);
			}
		}
		return newFrequency;

	}

	/**
	 * 
	 * @param values	beliebig
	 * @return			Die Häufigkeit der Merkmalskombination values; 0, wenn
	 * 					nicht vorhanden.
	 */
	public final long getCount(final Object... values) {
		List<Object> v = Arrays.asList(values);
		return getCount(v);
	}

	@Override
	public String toString() {
		Set<Entry<Collection<? extends Object>, Long>> set = getEntries();
		String s = "";
		for (Iterator<Entry<Collection<? extends Object>, Long>> iterator =
			set.iterator(); iterator.hasNext();) {
			Entry<Collection<? extends Object>, Long> entry = iterator.next();
			s += entry.getKey() + "\t" + entry.getValue();
			if (iterator.hasNext())
				s += "\n";
		}
		return s;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		CrossProductFrequency frequency = new CrossProductFrequency();
		frequency.incrementValues(1, "1", "a");
		frequency.incrementValues(2, "2", "a");
		frequency.incrementValues(3, "1", "b");
		frequency.incrementValues(4, "2", "b");

		System.out.println(frequency.getDistribution());
		System.out.println();
		System.out.println(frequency);
		System.out.println();
		System.out.println(frequency.getPartialSum(0));
		System.out.println();
		System.out.println(frequency.getPartialSum(1, 0));
		System.out.println();
		System.out.println(frequency.getCount("1", "a"));
		System.out.println(frequency.getCount("1", "x"));

		ArrayList<String> list = new ArrayList<>();
		list.add("1");
		list.add("a");
		frequency.increment(list, 1);

		System.out.println(frequency);
	}

}
